package com.zoro.barn.commons.webcommons.feign;

import com.zoro.barn.commons.foundation.web.FeignRequestEncoder;
import com.zoro.barn.commons.tools.json.JsonUtil;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhaoxingwu
 */
public class BarnRequestEncoder implements Encoder {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final List<FeignRequestEncoder> requestEncoders = new ArrayList<>();
    private final Encoder encoder;

    public BarnRequestEncoder(Encoder encoder) {
        this.encoder = encoder;
    }

    public void addRequestHandler(FeignRequestEncoder encoder) {
        this.requestEncoders.add(encoder);
    }

    @Override
    public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {

        if (this.encoder != null) {
            this.encoder.encode(object, bodyType, template);
        }

        if (CollectionUtils.isEmpty(requestEncoders)) {
            return;
        }

        Object result = object;
        for (FeignRequestEncoder requestEncoder : requestEncoders) {
            try {
                result = requestEncoder.encode(result, bodyType, object);

                if (logger.isDebugEnabled()) {
                    logger.debug("request : {}, encoder: {}, request data: {}",
                            template.request(), requestEncoder.getClass().getName(), result);
                }
                if (!logger.isDebugEnabled()) {
                    Logger requestLogger = LoggerFactory.getLogger(template.url());
                    if (requestLogger.isDebugEnabled()) {
                        requestLogger.debug("request : {}, encoder: {}, request data: {}",
                                template.request(), requestEncoder.getClass().getName(), result);
                    }
                }

            } catch (Exception e) {
                throw new EncodeException("encode data error, type : " + bodyType.getTypeName() +
                        "encoder : " + requestEncoder.getClass().getName(), e);
            }
        }

        try {
            template.body(JsonUtil.toString(result));
        } catch (Exception e) {
            throw new EncodeException("data to json error", e);
        }

    }
}
